//
//  SWCell.m
//  White Detector Grid
//
//  Created by David Langford on 9/05/09.
//  Copyright 2009 Sentient Worlds. All rights reserved.
//

#import "SWCell.h"
#import <OpenGL/CGLMacro.h>

@implementation SWCell

@synthesize xInPixels
			, yInPixels
			, widthInPixels
			, heightInPixels
			, weight;

- (id) initWithXPositionAt:(int)startXposition
			   yPositionAt:(int)startYposition
			 widthInPixels:(int)startWidth
			heightInPixels:(int)startHeight
{
	// Validate the arguments
	if (startXposition < 0
		|| startYposition < 0
		|| startWidth < 1
		|| startHeight < 1)
	{
		[self release];
		return nil;
	}
	
	
	if (self = [super init])
	{
		// NSNumber* that are copy need to be released
		self.xInPixels = startXposition;
		self.yInPixels = startYposition;
		self.widthInPixels = startWidth;
		self.heightInPixels = startHeight;
	}
	return self;
}

- (void) dealloc
{
	[super dealloc];
}

// Generates the weight for the cell
- (BOOL) generateWeightFromImage:(id<QCPlugInInputImageSource>)imageToUse
					   inContext:(id<QCPlugInContext>)theContext
{
	// Detect the white in this image
	vImage_Buffer					buffer;
	vImage_Error					error;
	vImagePixelCount*				histograms[4];
	
	if (imageToUse) {

		// Generate buffer depending on where this cell exists relative to the image
		int pixelSizeInBytes = 4;
		buffer.width = self.widthInPixels;
		buffer.height = self.heightInPixels;
		buffer.rowBytes = [imageToUse bufferBytesPerRow];
		buffer.data = (void*)([imageToUse bufferBaseAddress]					// Start at the image root
							  + (buffer.rowBytes*self.yInPixels)		// Go to the correct row
							  + (pixelSizeInBytes*self.xInPixels)	// Go to the correct pixel
							  );

		histograms[0] = _histogramA;
		histograms[1] = _histogramR;
		histograms[2] = _histogramG;
		histograms[3] = _histogramB;
		error = vImageHistogramCalculation_ARGB8888(&buffer, histograms, 0);
		
		
		if (error != kvImageNoError)
			return NO;
	}
	
	// Store buffer values
	histograms[0] = _histogramR;
	histograms[1] = _histogramG;
	histograms[2] = _histogramB;
	histograms[3] = _histogramA;
	
	// Generate the weight
	self.weight = [self generateWeightFromHistogram:histograms
									   usingChannel:1];
	
	return YES;
}

// Find what intensity has the highest amount of pixels
-(double) generateWeightFromHistogram:(vImagePixelCount**)histograms
							usingChannel:(int)channel;
{
	int numberOfIntensityChannels = 256;
	int currentHighestChannel = 0;
	int currentHighestNumberOfPixels = 0;
	
	for (int i=0; i<numberOfIntensityChannels; i++) {
		int numberOfPixels = histograms[channel][i];
		if (numberOfPixels > currentHighestNumberOfPixels)
		{
			currentHighestChannel = i;
			currentHighestNumberOfPixels = numberOfPixels;
		}
	}
	
	return currentHighestChannel/255.0;
}


// Returns an NSArray representing itself (the co-ordinet system will be changed from image pixels to quartz units
// The width, height, x and y will be normalised to the destination width and heights (units)
// The desitination width and height is the area that the grid is in, if used against an image it should be the image width and height
- (NSArray*) asNSArrayWithDestinationWidthInPixels:(double)destinatinoWidthInPixels
					 destinationAreaHeightInPixels:(double)destinationHeightInPixels
						   destinationWidthInUnits: (double)destinationWidthInUnits
						  destinationHeightInUnits: (double)destinationHeightInUnits
								destinationXOffset: (double)destinationXOffsetInUnits
								destinationYOffset: (double)destinationYOffsetInUnits
{

	// Create x,y, width and height values that are in units instead of pixels.
	double x = (self.xInPixels/destinatinoWidthInPixels)*destinationWidthInUnits;
	double y = (self.yInPixels/destinationHeightInPixels)*destinationHeightInUnits;
	double width= (self.widthInPixels/destinatinoWidthInPixels)*destinationWidthInUnits;
	double height = (self.heightInPixels/destinationHeightInPixels)*destinationHeightInUnits;
	
	// Handle the fact that the point of origin changed from the top left of the destination area to the centre of the destination area.
	// The new destination area is not in the centre of the cell.
	x = x - destinationWidthInUnits/2;
	y = y - destinationHeightInUnits/2;
	x = x + width/2;
	y = y + height/2;
	
	// Handle the flipping of the y axis
	y = y*-1;
	
	// Offset the grid
	x = x + destinationXOffsetInUnits;
	y = y + destinationYOffsetInUnits;
	
	return [NSArray arrayWithObjects: [NSNumber numberWithDouble:x]
										, [NSNumber numberWithDouble:y]
										, [NSNumber numberWithDouble:width]
										, [NSNumber numberWithDouble:height]
										, [NSNumber numberWithDouble:self.weight]
										, nil];
}

// Return a description of this grid
- (NSString*) description
{
	NSMutableString* description = [[NSMutableString alloc] initWithString:@"Cell Instance"];
	[description appendFormat:@"\n\tX position in pixels: %i", self.xInPixels];
	[description appendFormat:@"\n\tY position in pixels: %i", self.yInPixels];
	[description appendFormat:@"\n\tWidth in pixels: %i", self.widthInPixels];
	[description appendFormat:@"\n\tHeight in pixels: %i", self.heightInPixels];
	[description appendFormat:@"\n\tWeight: %i by %i", self.weight];
	return description;
}


@end
